package com.zhm.demo.netty.init;


import com.zhm.demo.netty.protobuf.DeviceBean;
import com.zhm.demo.netty.bean.TcpClient;
import com.zhm.demo.utils.SpringUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.Map;
import java.util.concurrent.*;

/**
 * @author hufei
 * @title
 * @description
 * @updateTime 2024/1/6 17:59
 */
@Component
public class HeroTcpClientManager {

    private static final Logger log = LoggerFactory.getLogger(HeroTcpClientManager.class);


    private static HeroTcpClientManager INSTANCE;

    private static final ConcurrentMap<String, TcpClient> connectionMaps = new ConcurrentHashMap<>();

    private static final long CLEANUP_INTERVAL = 1; // 清理间隔，单位：分钟

    /**
     * 用户连接map，尝试解决同一个用户在不同手机登录APP
     */
    public static final ConcurrentMap<String, ConcurrentMap<String, TcpClient>> connectionMap = new ConcurrentHashMap<>();

    /**
     * 进行初始化
     */
    private void init(HeroTcpClientManager manager) {
        INSTANCE = manager;
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        // 定期清理任务
        scheduler.scheduleAtFixedRate(this::cleanupConnections, CLEANUP_INTERVAL, CLEANUP_INTERVAL, TimeUnit.MINUTES);
    }

    public HeroTcpClientManager() {
        init(this);
    }

    public static HeroTcpClientManager getInstance() {
        return INSTANCE;
    }

    public void addConnection(TcpClient connection) {
        connectionMaps.put(connection.getUserId(), connection);


        ConcurrentMap<String, TcpClient> userConnectionMap; // 单个用户已建立的连接，已token为key
        // 取出当前用户的连接
        if (connectionMap.containsKey(connection.getUserId())) {
            userConnectionMap = connectionMap.get(connection.getUserId());
        } else {
            // 用户未创建过连接，创建一个map存储用户连接
            userConnectionMap = new ConcurrentHashMap<>();
            connectionMap.put(connection.getUserId(), userConnectionMap);
        }
        if (!userConnectionMap.containsKey(connection.getAuthorization())) {
            // 存储用户当前token对应的连接
            userConnectionMap.put(connection.getAuthorization(), connection);
            log.info("新增用户连接：userId={},token={}", connection.getUserId(), connection.getAuthorization());
        }
    }

    public TcpClient getConnection(String connectionId) {
        return connectionMaps.get(connectionId);
    }

    public Boolean isRegister(String id) {
        return connectionMaps.containsKey(id);
    }

    public void removeConnection(String connectionId) {
        connectionMaps.remove(connectionId);
    }

    // 定期清理无效连接
    private void cleanupConnections() {
        for (Map.Entry<String, TcpClient> entry : connectionMaps.entrySet()) {
            String connectionId = entry.getKey();
            TcpClient connection = entry.getValue();
            checkAndCleanupConnection(connectionId, connection);
        }
    }

    // 根据实际情况实现该方法，检查连接是否有效，并进行清理
    private void checkAndCleanupConnection(String connectionId, TcpClient connection) {
        // 处理心跳请求，发送心跳响应
        DeviceBean.Pong pong = DeviceBean.Pong.newBuilder().build();
        DeviceBean.WrapperMessage build = DeviceBean.WrapperMessage.newBuilder().setType(DeviceBean.WrapperMessage.MessageType.Pong).setPong(pong).build();
        Channel channel = connection.getChannel();
        // 添加ChannelFuture的监听器
        ChannelFuture channelFuture = channel.writeAndFlush(build);
        channelFuture.addListener((future) -> {
            if (future.isSuccess()) {
                // 异步操作成功，连接有效
                System.out.println("Heartbeat sent successfully");
            } else {
                // 异步操作失败，连接无效，可以在这里处理连接无效的逻辑
                System.out.println("Failed to send heartbeat, marking connection as invalid");
                removeConnection(connectionId);
            }
        });
    }

    public static void writeAndFlush(DeviceBean.WrapperMessage wrapperMessage, String userId) {
        HeroTcpClientManager tcpClientManager = SpringUtils.getBean(HeroTcpClientManager.class);
        TcpClient connection = tcpClientManager.getConnection(userId);
        if (ObjectUtils.isEmpty(connection)) {
            log.error("sendPower,但是连接为空+userId=" + userId);
            return;
        }
        connection.getChannel().writeAndFlush(wrapperMessage);
    }
}
